package com.erbantou.filemanage.progress;

import org.apache.http.Header;
import org.apache.http.HttpEntity;

import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class ProgressHttpEntityWrapper implements HttpEntity {
    private final HttpEntity originalEntity;
    private final ProgressListener progressListener;

    public ProgressHttpEntityWrapper(HttpEntity originalEntity, ProgressListener progressListener) {
        this.originalEntity = originalEntity;
        this.progressListener = progressListener;
    }

    @Override
    public boolean isRepeatable() {
        return originalEntity.isRepeatable();
    }

    @Override
    public boolean isChunked() {
        return originalEntity.isChunked();
    }

    @Override
    public long getContentLength() {
        return originalEntity.getContentLength();
    }

    @Override
    public boolean isStreaming() {
        return originalEntity.isStreaming();
    }

    @Override
    public Header getContentType() {
        return originalEntity.getContentType();
    }

    @Override
    public Header getContentEncoding() {
        return originalEntity.getContentEncoding();
    }

    @Override
    public InputStream getContent() throws IOException {
        return originalEntity.getContent();
    }

    @Override
    public void writeTo(OutputStream outstream) throws IOException {
        originalEntity.writeTo(new CountingOutputStream(outstream, progressListener, getContentLength()));
    }

    @Override
    public void consumeContent() throws IOException {
        originalEntity.consumeContent();
    }
}

class CountingOutputStream extends FilterOutputStream {
    private final ProgressListener progressListener;
    private final long totalSize;
    private long transferred;
    private long lastUpdate = 0;

    public CountingOutputStream(OutputStream out, ProgressListener progressListener, long totalSize) {
        super(out);
        this.progressListener = progressListener;
        this.transferred = 0;
        this.totalSize = totalSize;
    }

    @Override
    public void write(byte[] b, int off, int len) throws IOException {
        out.write(b, off, len);
        this.transferred += len;
        maybeUpdateProgress();
    }

    @Override
    public void write(int b) throws IOException {
        out.write(b);
        this.transferred++;
        maybeUpdateProgress();
    }

    private void maybeUpdateProgress() {
        // 500 KB
        long updateThreshold = 1024 * 500L;
        if (this.transferred - this.lastUpdate > updateThreshold || this.transferred == this.totalSize) {
            this.lastUpdate = this.transferred;
            this.progressListener.transferred(this.transferred, this.totalSize);
        }
    }
}
